package cn.sdxx.qddata.security;


import cn.sdxx.qddata.entity.User;
import cn.sdxx.qddata.service.UserService;
import cn.sdxx.qddata.utils.JwtTokenUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

@Slf4j
@Component
public class UserRealm extends AuthorizingRealm {

    @Autowired
    JwtTokenUtils jwtTokenUtils;

    @Autowired
//    @Lazy
    UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("授权：jwt-------------->{}", principals);
        //由于 doGetAuthenticationInfo方法返回值中，将user作为principals
        //因此principals.getPrimaryPrincipal()拿到的是user
        //权限校验和赋予
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Set<String> roles = new HashSet<>();
        //到数据库中查询角色信息
        User principal = (User) principals.getPrimaryPrincipal();
        System.out.println("principal = " + principal);
        roles.add("admin");
        authorizationInfo.setRoles(roles);
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        JwtToken jwtToken = (JwtToken) token;  // 这是前端传来的jwt

        //principal是Redis缓存中的key
        String principal = (String) jwtToken.getPrincipal();  //principal实际是token
        String credentials = (String) jwtToken.getCredentials();
        Claims claims = jwtTokenUtils.parseToken(principal);
        //  判断是否已过期
        if(claims == null || jwtTokenUtils.isTokenExpired(claims.getExpiration())) {
            throw new AuthenticationException("token已失效，请重新登录！");
//            throw new ExpiredCredentialsException("token已失效，请重新登录！");
        }
        String username = claims.getId();
        log.info("shiro登录认证：jwt-------------->{}", username);

        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getUsername, username);
        User userAccount = userService.getOne(lqw);
        if (userAccount == null) {
            throw new UnknownAccountException("账户不存在！");
        }
        // 将user作为 Principal
        // 由于shiro-redis插件需要从这个属性中获取id作为redis的key
        // 所有这里传的是user对象，而不是username
        // 【缓存Authentication时用的key是token.getPrincipal()】
        return new SimpleAuthenticationInfo(username, credentials, getName());
    }

    //给此realm的token类型必须是supports方法所支持的，才会执行doGetAuthenticationInfo方法
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }
}
